package com.meme.app;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.io.File;

import javax.swing.AbstractAction;
import javax.swing.Icon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane; 

import javax.swing.JOptionPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.filechooser.FileNameExtensionFilter;

import com.meme.editor.gui.sprite2d.Sprite2dMainPanel;
import com.meme.editor.model.sprite2d.Sprite2dFile;

import com.meme.editor.level.LevelFile;
import com.meme.editor.gui.level.LevelMainPanel;

import com.meme.editor.EntityObject;


import com.meme.io.editor.FileCache;
import com.meme.io.editor.Sprite2dXmlFileWriter;

import com.meme.util.GuiUtil;
import com.meme.util.FileUtil;

import com.meme.editor.gui.FileEditor;



import org.apache.log4j.Logger;

import java.util.Hashtable;


public class Suit2dMainFrame extends JFrame
{
	static Logger logger = Logger.getLogger (Suit2dMainFrame.class);
	
	JToolBar    mToolBar;
	JTabbedPane mTabbedPanel;
	
	Suit2dMainFrame mThisMainFrame;
	
	
	public Suit2dMainFrame ()
	{
		super ("Suited Editor");
		
		//JRootPane rootpanel = getRootPane();
        Container rootpanel =  getContentPane ();
		rootpanel.setLayout ( new BorderLayout() );
		
		// create actions
		NewFileAction  newSprite2dAction  = new NewFileAction (ResourceManager.getIcon("new"), FileType_Sprite2dModel);
		NewFileAction  newLevelAction  = new NewFileAction (ResourceManager.getIcon("new"), FileType_Level2d);
		OpenFileAction openaction = new OpenFileAction(ResourceManager.getIcon("open"));
		SaveFileAction saveaction = new SaveFileAction(ResourceManager.getIcon("save"));
		SaveFileAsAction saveasaction = new SaveFileAsAction (null);
		CloseFileAction closeaction = new CloseFileAction(ResourceManager.getIcon("close"));
		
		// menu
        JMenuBar menubar = new JMenuBar ();
        {
        	JMenu menu = new JMenu ("File"); 
            menubar.add (menu);
            
            menu.add (newSprite2dAction);
            menu.add (newLevelAction);
            menu.addSeparator();
            menu.add (openaction);
            menu.addSeparator();
            menu.add (saveaction);
            menu.add (saveasaction);
            menu.addSeparator();
            menu.add (closeaction);
        }
        
        setJMenuBar ( menubar );
        
        // tool bar
        mToolBar = new JToolBar ();  
        mToolBar.setFloatable (false);
        mToolBar.setRollover ( true );
        mToolBar.add (newSprite2dAction);
        mToolBar.add (newLevelAction);
        mToolBar.add (openaction);
        mToolBar.add (saveaction);
        mToolBar.addSeparator();
        

        
        JToolBar toolbar2 = new JToolBar ();
        toolbar2.setFloatable (false);
        toolbar2.setRollover ( true );
        toolbar2.add (closeaction);
        
        JPanel toppanel = new JPanel ();
        toppanel.setLayout(new BorderLayout());       
        toppanel.add (mToolBar, BorderLayout.CENTER);
        toppanel.add (toolbar2, BorderLayout.EAST);		
		
        rootpanel.add (toppanel, BorderLayout.NORTH);
        
		// main content panel
        mTabbedPanel = new JTabbedPane ();
        mTabbedPanel.setPreferredSize (new java.awt.Dimension(800, 600));
        rootpanel.add (mTabbedPanel, BorderLayout.CENTER);

        
        // ...

        
        mThisMainFrame = this;
	}
	
	
	Hashtable<Object, FileEditor> mFileAsset2FileEditorTable = new Hashtable <Object, FileEditor>();
	Hashtable<FileEditor, Object> mFileEditor2FileAssetTable = new Hashtable <FileEditor, Object>();

	void addFileAssetFileEditorPair (Object fileAsset, FileEditor fileEditor)
	{
		mFileAsset2FileEditorTable.put(fileAsset, fileEditor);
		mFileEditor2FileAssetTable.put(fileEditor, fileAsset);
	}
	
	void removeFileAssetFileEditorPair (Object fileAsset, FileEditor fileEditor)
	{
		FileEditor editor = fileAsset  == null ? fileEditor : mFileAsset2FileEditorTable.get (fileAsset);
		Object     asset  = fileEditor == null ? fileAsset  : mFileEditor2FileAssetTable.get (fileEditor);
		if (fileAsset  == null) fileAsset  = asset;
		if (fileEditor == null) fileEditor = editor;
		
		logger.assertLog(editor == fileEditor && asset == fileAsset, "Pair not matched.");
		
		logger.assertLog ( (fileAsset != null) == (fileEditor != null), "?");
		
		if (fileAsset != null && fileEditor != null)
		{
			mFileAsset2FileEditorTable.remove (fileAsset);
			mFileEditor2FileAssetTable.remove (fileEditor);
		}
	}
	
    void createFileEditor (Object fileAsset)
    {
    	FileEditor fileEditor = null;
    	String tabName = null;
    	
		if (fileAsset instanceof LevelFile)
		{
			LevelFile levelFile = (LevelFile)fileAsset;
			fileEditor = new LevelMainPanel (levelFile);
			tabName = levelFile.getName();
		}
		else if (fileAsset instanceof Sprite2dFile)
		{
			Sprite2dFile sprite2dFile = (Sprite2dFile)fileAsset;
			fileEditor = new Sprite2dMainPanel(sprite2dFile);
			tabName = sprite2dFile.getName();
		}
		
		if (fileEditor != null)
		{
	    	mTabbedPanel.add (tabName, fileEditor.getComponent());
	    	mTabbedPanel.setSelectedComponent(fileEditor.getComponent());
	    	
	    	addFileAssetFileEditorPair (fileAsset, fileEditor);
		}
    }
    
    public boolean closeAllFileEditors ()
    {
    	
    	do 
    	{
    		int index = mTabbedPanel.getSelectedIndex();
    		
    		if (index < 0) 
    			return true;
    		
    		if (! onClose ())
    			return false;
    		
    	} while (true);
    }
	
//----------------------------------------------------------------------------------------
// actions
//----------------------------------------------------------------------------------------

	final static int FileType_Sprite2dModel = 0;
	final static int FileType_Level2d = 1;
	
	static String getNewCommandString (int fileType)
	{
		String title;
		switch (fileType)
		{
		case FileType_Sprite2dModel:
			title = "New Sprite 2d";
			break;
		case FileType_Level2d:
			title = "New Level 2d";
			break;
		default:
			title = "New ...";
		}
		
		return title;
	}
	
	class NewFileAction extends AbstractAction 
	{
		int mFileType;
		
		public NewFileAction (Icon icon)
		{
			this (icon, FileType_Sprite2dModel);
		}

		
		public NewFileAction (Icon icon, int fileType)
		{
			super (getNewCommandString (fileType), icon);
			
			mFileType = fileType;
		}
				
	    public void actionPerformed(ActionEvent e) 
	    {
	    	FileEditor fileEditor;

	    	switch (mFileType)
	    	{
			case FileType_Sprite2dModel:
				Sprite2dFile sprite2dFile = new Sprite2dFile();
				
				createFileEditor (sprite2dFile);
				break;
			case FileType_Level2d:
				LevelFile levelFile = new LevelFile ();
				
				createFileEditor (levelFile);
				break;
			default:
				logger.error ("Unknown file type.");
	    		return;
	    	}

	    }
	}
	
	class OpenFileAction extends AbstractAction 
	{
		public OpenFileAction (Icon icon)
		{
			super ("Open ...", icon);
		}
		
	    public void actionPerformed(ActionEvent e)
	    {
	    	String filename = GuiUtil.popupFileChooser(mThisMainFrame, "Open ...", true, new String[] {Sprite2dFile.getFileExtension(), LevelFile.getFileExtension()}, "Editor Files", null);
	    	if ( filename != null )
	    	{
    			Object fileAsset = FileCache.getLoadedFileAsset(filename);
    			
    			if (fileAsset != null)
    			{
    				FileEditor fileEditor = mFileAsset2FileEditorTable.get (fileAsset);
    				
    				if (fileEditor != null)
    				{
	    				Component component = fileEditor.getComponent();
	    				
	    				logger.assertLog (component != null, "component should not be null.");
	    				
	    				mTabbedPanel.setSelectedComponent (component);
    				}
    				else
    				{
    					createFileEditor (fileAsset);
    				}

    					
    				return;
    			}
    			
	    		String ext = FileUtil.getFilenameExt(filename).toLowerCase(); 
	    		if (ext.equals("xlevel"))
	    		{
	    			LevelFile levelFile = FileCache.getLevelFile (filename);
	    			levelFile.setModified (false);
	    			
	    			createFileEditor (levelFile);
			    }
	    		else
	    		{
			    	//Sprite2dFile sprite2dFile = Sprite2dFileLoader.loadFromFile(filename);
			    	Sprite2dFile sprite2dFile = FileCache.getSprite2dFile (filename);
			    	sprite2dFile.setModified(false);
			    	
			    	createFileEditor (sprite2dFile);
	    		}
		    }
	    }
	    

	}
	
	class SaveFileAction extends AbstractAction 
	{
		public SaveFileAction (Icon icon)
		{
			super ("Save ...", icon);
		}
		
	    public void actionPerformed(ActionEvent e) 
	    {
	    	onSave ();
	    }
	}
	
	public boolean onSave ()
	{
    	int index = mTabbedPanel.getSelectedIndex();
    	if ( index >= 0 )
    	{
    		FileEditor fileEditor = (FileEditor) mTabbedPanel.getComponentAt(index);
    		if( fileEditor.isFileNew() )
    			return onSaveAs ();
    		else
    			fileEditor.onSaveFile(null);
    	}
    	
    	return true;
	}
	
	class SaveFileAsAction extends AbstractAction 
	{
		public SaveFileAsAction (Icon icon)
		{
			super ("Save As ...", icon);
		}
		
	    public void actionPerformed(ActionEvent e) 
	    {
	    	onSaveAs ();
	    }
	}

	public boolean onSaveAs ()
	{
    	int index = mTabbedPanel.getSelectedIndex();
    	if ( index >= 0 )
    	{
    		FileEditor fileEditor = (FileEditor) mTabbedPanel.getComponentAt(index);

			while (true)
			{
				Object fileAsset = mFileEditor2FileAssetTable.get(fileEditor);
	    		String defaultFilename = "?";
	    		if (fileAsset instanceof EntityObject)
	    		{
	    			defaultFilename = ( (EntityObject) fileAsset ).getHostFilename();
	    		}
	    						
				
		    	String filename = GuiUtil.popupFileChooser(mThisMainFrame, "Save As ...", false, 
		    			(fileAsset instanceof Sprite2dFile) ? Sprite2dFile.getFileExtension() : LevelFile.getFileExtension(), 
		    			(fileAsset instanceof Sprite2dFile) ? "Sprite2d File" : "Level File", 
		    			defaultFilename);
		    	if ( filename == null )
		    		return false;
		    	
	    		File file = FileUtil.getFile (filename);
	    		
	    		if (file.exists())
	    		{
	       			Object[] options = {"Yes", "No"};
	    			int n = JOptionPane.showOptionDialog( mThisMainFrame,
						        "File already exists, override it?",
						        "?",
						        JOptionPane.YES_NO_OPTION,
						        JOptionPane.QUESTION_MESSAGE,
						        null,
						        options,
						        options[1]);
	    			
	    			if (n == 1)
	    				continue;
	    		}
	
	    		fileEditor.onSaveFile (filename);
	    		
	    		break;
			};
			
			mTabbedPanel.setTitleAt (index, fileEditor.getTitle());
    	}
		
		return true;
	}
	
	
	class CloseFileAction extends AbstractAction 
	{
		public CloseFileAction (Icon icon)
		{
			super ("Close", icon);
		}
		
	    public void actionPerformed(ActionEvent e) 
	    {
	    	onClose ();
	    }
	}
	
	public boolean onClose ()
	{
    	int index = mTabbedPanel.getSelectedIndex();
    	if ( index >= 0 )
    	{
    		FileEditor fileEditor = (FileEditor) mTabbedPanel.getComponentAt(index);
    		Object fileAsset = mFileEditor2FileAssetTable.get(fileEditor);
    		String dialogTitle = "?";
    		if (fileAsset instanceof EntityObject)
    		{
    			dialogTitle = ( (EntityObject) fileAsset ).getName();
    		}
    		
    		if ( fileEditor.isFileModified() )
    		{
    			Object[] options = {"Yes", "No", "Cancel"};
    			int n = JOptionPane.showOptionDialog( mThisMainFrame,
					        "File changed, save it?",
					        dialogTitle,
					        JOptionPane.YES_NO_CANCEL_OPTION,
					        JOptionPane.QUESTION_MESSAGE,
					        null,
					        options,
					        options[2]);
    			
    			if (n == 0) // yes
    			{
    				if ( ! onSave () )
    					return false; // not save successfully
    			}
    			else if (n == 2) // cancel
    				return false;
    			else // no
    				;
    		}
    		
    		
	    	mTabbedPanel.remove(index);
	    	
	    	removeFileAssetFileEditorPair (null, fileEditor);
    	}

    	return true;
	}


}
